#include "softpointpwm.h"

//为了性能，可以去掉check
#define NEXT_POINT_MIN_LIMIT 10  //包含 下限和上限，10, period - 10

SoftPointPwm::SoftPointPwm()
{
}

SoftPointPwm::~SoftPointPwm()
{

}
void SoftPointPwm::AttachTimer(SOC_Timer *timer)
{
    DettachTimer();
    m_timer = timer;
    if(m_timer)
    { 
        SetPeriodNoTimer(m_timer->GetPeriod()); //同步period
        m_timer->SetOcCallBack([=](auto &sender, int channel){
            FW_UNUSED(sender);
            TimerHandler(channel);
        });
    }
    else
    {}
        SetPeriodNoTimer(0);
}

void SoftPointPwm::DettachTimer()
{
    if(m_timer == nullptr)
        return;

    StopAll();
    m_timer->SetOcCallBack(nullptr);
    m_timer = nullptr;
}

void SoftPointPwm::AttachGpio(int ch, const GpioPortPin &gpio, const GpioPortPin &gpioN)
{
    ASSERT_ARRAY_INDEX_1(m_pwmItems, ch);

    m_pwmItems[ch - 1].AttachGpio(gpio, gpioN);
}

void SoftPointPwm::DettachGpio(int ch)
{
    ASSERT_ARRAY_INDEX_1(m_pwmItems, ch);

    m_pwmItems[ch - 1].DettachGpio();
}

void SoftPointPwm::Config(int ch, bool isReverse, int normalValue, bool isSameWhenNormal)
{
    ASSERT_ARRAY_INDEX_1(m_pwmItems, ch);
    
    auto ptr = &m_pwmItems[ch - 1];
    ptr->IsReverse = isReverse;
    ptr->NormalValue = normalValue;
    ptr->IsSameWhenNormal = isSameWhenNormal;
}

void SoftPointPwm::SetPeriod(int period)
{
    m_timer->SetPeriod(period);
    SetPeriodNoTimer(period);
}

int SoftPointPwm::GetPeriod()
{
    return m_timerPeriod;
}

void SoftPointPwm::SetDuty(int ch, int duty)
{
    ASSERT_ARRAY_INDEX_1(m_pwmItems, ch);

    m_pwmItems[ch - 1].Duty = duty;
    
    // m_timer->StopOc_IT(ch);
    m_pwmItems[ch - 1].Update();
    // m_timer->StartOc_IT(ch);
}

int SoftPointPwm::GetDuty(int ch)
{
    ASSERT_ARRAY_INDEX_1(m_pwmItems, ch);
    
    return m_pwmItems[ch - 1].Duty;
}

bool SoftPointPwm::IsRunning(int ch)
{
    ASSERT_ARRAY_INDEX_1(m_pwmItems, ch);
    
    return m_pwmItems[ch - 1].IsRunning;
}

void SoftPointPwm::Start(int ch)
{
    m_PeriodCountMax = -1;
    Start(ch, m_PeriodCountMax);
}

void SoftPointPwm::Start(int ch, int periodCount)
{
    ASSERT_ARRAY_INDEX_1(m_pwmItems, ch);

    m_PeriodCountMax = periodCount;
    if(m_timer == nullptr)
        return;
    auto ptr = &m_pwmItems[ch - 1];
    if(ptr->IsRunning)
        return;
    
    //check
    if(!ptr->Check())
        return;

    //it is okay
    ptr->Begin();
    //first setting
    TimerHandler(ch);  
    m_timer->StartOc_IT(ch);
}

void SoftPointPwm::StartAll()
{
    if(m_timer == nullptr)
        return;
        
    for(int i = 1; i <= SOFT_PWM_POINT_MAX; i++)
    {
        Start(i);
    }
}

void SoftPointPwm::Stop(int ch)
{
    ASSERT_ARRAY_INDEX_1(m_pwmItems, ch);
    if(m_timer == nullptr)
        return;
    
    auto ptr = &m_pwmItems[ch - 1];
    if(!ptr->IsRunning)
        return;

    //先关闭IT
    m_timer->StopOc_IT(ch);
    ptr->End();
}

void SoftPointPwm::StopAll()
{
    if(m_timer == nullptr)
        return;
        
    for(int i = 1; i <= SOFT_PWM_POINT_MAX; i++)
    {
        Stop(i);
    }
}

void SoftPointPwm::TimerHandler(int ch)
{
    //不做异常判断了，加快性能
    auto ptr = &m_pwmItems[ch - 1];

    if(ptr)
    {
        int next = ptr->Next();
        //给定周期数
        if(m_PeriodCountMax > 0)
        {
            if(ptr->LastPoint == SoftPwmItem::PointPostion::P2)
            {
                m_PeriodCountMax --;
                if(m_PeriodCountMax == 0)
                {
                    Stop(ch);
                }
            }
        }

        m_timer->SetNextPoint(ch, next);
    }
}

void SoftPointPwm::SetPeriodNoTimer(int period)
{
    m_timerPeriod = period;
    for(int i = 0; i < SOFT_PWM_POINT_MAX; i++)
    {
        m_pwmItems[i - 1].Period = period;
    }
}
